package com.jt.aop;



import com.jt.anno.CacheFind;
import com.jt.unit.ObjectMapperUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.ShardedJedis;

import java.util.Arrays;

@Component//我时一个javabean
@Aspect //我是一个切面
public class CacheAOP {
    @Autowired
    JedisCluster jedis;
    /**
     * AOP缓存业务策略
     * 1切入点表达式应该拦截 @CacheFind注解
     * 2通知方法 环绕通知
     * 如果使用环绕通知 必须在第一个参数的位置添加ProceedingJoinPoint
     */
    @Around("@annotation(cacheFind)")
    public Object around(ProceedingJoinPoint joinPoint,CacheFind cacheFind){
        try {
            Object result=null;
            System.out.println("AOP环绕通知开始");
            //如何获取注解中的参数
            String prekey = cacheFind.key();
            //动态获取方法中的参数 将数组转化为字符串
            String args = Arrays.toString(joinPoint.getArgs());
            String key = prekey+"::"+args;
            //校验redis中是否有数据
            if(jedis.exists(key)){
                //有缓存  从redis缓存中获取json 然后还原对象返回
                String json = jedis.get(key);
                //target代表目标方法的返回值类型
                //动态获取目标方法的返回值对象
                MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
                Class returnClass = methodSignature.getReturnType();
                //将json数据转化为对象
                result = ObjectMapperUtil.toObject(json,returnClass);
                System.out.println("AOP实现缓存查询");
            }else{
                //第一次查询数据库
                result = joinPoint.proceed();
                String json = ObjectMapperUtil.toJson(result);
                if(cacheFind.seconds()>0){//需要设置超时
                    jedis.setex(key,cacheFind.seconds(),json);
                }else {
                    //不需要超时
                    jedis.set(key,json);
                }

            }
            return result;


        } catch (Throwable throwable) {
            throwable.printStackTrace();
            throw new RuntimeException(throwable);//将检查异常转化为运行时异常
        }

    }





    //定义切入点表达式
    @Pointcut("bean(itemCatServiceImpl)")
    public void pointCut(){

    }
    @Before("pointCut()")
    public void before(JoinPoint joinPoint){
        System.out.println("我是前置通知");
        //获取类名称
        String className = joinPoint.getSignature().getDeclaringTypeName();

        String methodName = joinPoint.getSignature().getName();
        //获取目标方法对象
        Object target = joinPoint.getTarget();
        //获取目标方法参数
        Object[]objs = joinPoint.getArgs();

        System.out.println("方法名"+methodName);
        System.out.println("对象"+target);
        System.out.println("方法参数"+objs);

    }
}
